using System;
using System.Collections.Generic;
using System.Linq;
using FishFillets.Model;
using FishFillets.Model.GameItems;
using Microsoft.Xna.Framework;

namespace FishFillets.ObjectLogic
{
    /// <summary>
    /// Class responsible hor hanlding move events on Level, updating all items position,
    /// saving and loading saved games.
    /// This class should be accessible via some interface / dependency injection.
    /// </summary>
    public class LevelManager
    {
        public Level Level { get; set; }

        public Fish Fish
        {
            get { return fish; }
            set
            {
                if (fish != null) fish.Active = false;
                fish = value;
                if (fish != null) fish.Active = true;
            }
        }
        private Fish fish;

        public void LoadLevel(Level level)
        {
            Level = level;
            Fish = level.Big;
            FallAll(Level.AllItems.Where(i => i.Weight < ItemWeight.Fixed).ToList(), Level.AllItems);
        }

        public void UnloadLevel()
        {
            Level = null;
            Fish = null;
        }

        public void SwitchPlayer()
        {
            if (Level == null) return;

            Fish = Fish == Level.Big ? Level.Small : Level.Big;
        }

        public bool Move(Direction dir)
        {
            if (Level == null || Fish == null) return false;

            bool moved = false;
            if (MoveRulesManager.CanMove(Fish, dir, Fish.Strength, Level.AllItems.Except(new[] { Fish }).ToList()))
            {
                List<BaseItem> movedItems = MoveRulesManager.GetMovedoObjects(Fish, dir, Level.AllItems);
                Move(dir, movedItems);
                FallAll(Level.AllItems.Where(i => i.Weight < ItemWeight.Fixed).ToList(), Level.AllItems);
                moved = true;
            }
            return moved;
        }

        private void FallAll(List<BaseItem> itemsToFall, List<BaseItem> allItems)
        {
            do
            {
                itemsToFall = itemsToFall.Where(o => MoveRulesManager.CanFall(o, allItems)).ToList();
                Move(Direction.Down, itemsToFall);
            } while (itemsToFall.Any());
        }

        private static void Move(Direction dir, List<BaseItem> movedObjects)
        {
            foreach (BaseItem item in movedObjects)
            {
                MoveItem(item, dir);
            }
        }

        private static void MoveItem(BaseItem item, Direction dir)
        {
            switch (dir)
            {
                case Direction.Up:
                    item.Position = new Point(item.Position.X, item.Position.Y - 1);
                    break;
                case Direction.Down:
                    item.Position = new Point(item.Position.X, item.Position.Y + 1);
                    break;
                case Direction.Left:
                    item.Position = new Point(item.Position.X - 1, item.Position.Y);
                    break;
                case Direction.Right:
                    item.Position = new Point(item.Position.X + 1, item.Position.Y);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("dir");
            }
        }
    }
}
